package lib.bone.admin.controller.flow;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lib.bone.admin.anno.WebLog;
import lib.bone.admin.constant.MethodTypeConst;
import lib.bone.audit.domain.vo.FlowWorkLinkVO;
import lib.bone.audit.workload.service.NepuWorkloadService;
import lib.bone.common.constant.ResponseCodeConst;
import lib.bone.common.core.domain.ResponseDTO;
import lib.bone.common.utils.JsonUtil;
import lib.bone.flow.constant.FlowTaskStatusConst;
import lib.bone.flow.constant.FlowWorkStatusConst;
import lib.bone.flow.domain.dto.FlowParam;
import lib.bone.flow.domain.dto.FlowWorkQueryDTO;
import lib.bone.flow.domain.entity.FlowTask;
import lib.bone.flow.domain.entity.FlowWork;
import lib.bone.flow.domain.model.BaseModel;
import lib.bone.flow.domain.model.FlowModel;
import lib.bone.flow.domain.model.TaskModel;
import lib.bone.flow.event.FlowWorkRemoveEvent;
import lib.bone.flow.module.loader.FlowNodeUserLoader;
import lib.bone.flow.module.parser.FlowNodeParser;
import lib.bone.flow.module.processor.impl.TaskNodeProcessorImpl;
import lib.bone.flow.service.FlowAttachService;
import lib.bone.flow.service.FlowTaskService;
import lib.bone.flow.service.FlowWorkService;
import lib.bone.nepudata.service.NepuEntityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;

import javax.transaction.Transactional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author: kindear
 */
@Slf4j
@RestController
@RequestMapping("flow")
@Api(tags = "流程实例")
public class FlowWorkController {
    @Autowired
    FlowWorkService flowWorkService;

    @Autowired
    FlowTaskService taskService;

    @Autowired
    FlowNodeParser flowNodeParser;

    @Autowired
    NepuEntityService entityService;

    @Autowired
    FlowAttachService attachService;

    @Autowired
    NepuWorkloadService workloadService;

    @Autowired(required = false)
    FlowNodeUserLoader flowNodeUserLoader;

    @Autowired(required = false)
    FlowWorkRemoveEvent removeEvent;

    @Autowired
    TaskNodeProcessorImpl taskNodeProcessor;

    @WebLog(module = "bone-flow",operate = MethodTypeConst.UPDATE)
    @PostMapping("work/{workId}/cancel")
    @ApiOperation(value = "取消流程")
    public ResponseDTO<FlowWork> cancelFlowWork(@PathVariable("workId") String workId){
        // 1. 查询当前流程状态
        Optional<FlowWork> flowWorkOp = flowWorkService.getById(workId);
        if (!flowWorkOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"未查询到该流程信息");
        }
        FlowWork work = flowWorkOp.get();
        if (work.getStatus().equals(0)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"该流程已被关闭");
        }
        // 2. 查询流程锁定态，是否可以被取消
        if (work.getLocked().equals(1)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"流程已处于审核流程中，请等待审核完成");
        }
        // 3. 清理所有相关的 task 任务
        taskService.deleteFlowTasks(workId);
        // 4. 修改流程状态为已取消
        work.setFlowWorkStatus(FlowWorkStatusConst.CANCEL);
        return flowWorkService.updateWork(work);
    }

    /**
     * 获取ID 对应的flowwork 信息
     */
    @GetMapping("work/{id}")
    @ApiOperation(value = "查询流程实例信息",notes = "传入ID")
    public ResponseDTO<FlowWork> getFlowWork(@PathVariable("id") String id){
        Optional<FlowWork> flowWorkOp = flowWorkService.getById(id);
        return flowWorkOp.map(ResponseDTO::succData).orElseGet(() -> ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND));
    }


//    @WebLog(module = "bone-flow",operate = MethodTypeConst.DELETE)
    @DeleteMapping("work/{id}")
    @ApiOperation(value = "删除流程实例信息",notes = "传入ID")
    public ResponseDTO deleteFlowWork(@PathVariable("id") String id){
        // 移除事件触发 -- 删除实体和工作量相关信息
        if (!Validator.isEmpty(removeEvent)){
            removeEvent.process(id);
        }
        // 删除关联的流程流转信息
        attachService.deleteByFlow(id);
        // 删除关联的任务审核记录
            taskService.deleteFlowTasks(id);
        // 删除流程信息
        flowWorkService.deleteFlow(id);
        return ResponseDTO.succMsg("删除流程实例成功");
    }





    @GetMapping("work/list/check")
    @ApiOperation(value = "查询流程实例关联状态(ID-List)",notes = "")
    public ResponseDTO checkFlowWorkList(@RequestParam("flowWorkIds") List<String> flowWorkIds){
        List<FlowWork> flowWorks = flowWorkService.getFlowWorksByIds(flowWorkIds);

        List<Future<FlowWorkLinkVO>> list = new ArrayList<>();
        // 构建返回值列表
        List<FlowWorkLinkVO> ans = new ArrayList<>();

        flowWorks.forEach(ele->{
            list.add(workloadService.checkFlowWorkWithWorkload(ele));
        });

        for (int i = 0; i < list.size(); i++){
            try {
                Future<FlowWorkLinkVO> r = list.get(i);
                ans.add(r.get());
            } catch (InterruptedException | ExecutionException e) {
                // Handle appropriately, results.add(null) or just leave it out
                log.error(e.toString());
            }
        }
        return ResponseDTO.succData(ans);
    }


    @GetMapping("work/check")
    @ApiOperation(value = "查询流程实例关联状态(Example)",notes = "pageSize和pageNum 此处为无用参数")
    public ResponseDTO checkFlowWorkList(FlowWorkQueryDTO dto){
        FlowWork flowWork = new FlowWork();
        BeanUtil.copyProperties(dto,flowWork, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        Example<FlowWork> example = Example.of(flowWork);
        // 获取全部符合条件的流程实例
        List<FlowWork> flowWorks = flowWorkService.getAllFlowWork(example);

        List<Future<FlowWorkLinkVO>> list = new ArrayList<>();

        // 构建返回值列表
        List<FlowWorkLinkVO> ans = new ArrayList<>();

        flowWorks.forEach(ele->{
            list.add(workloadService.checkFlowWorkWithWorkload(ele));
        });

        for (int i = 0; i < list.size(); i++){
            try {
                Future<FlowWorkLinkVO> r = list.get(i);
                ans.add(r.get());
            } catch (InterruptedException | ExecutionException e) {
                // Handle appropriately, results.add(null) or just leave it out
                log.error(e.toString());
            }
        }
        return ResponseDTO.succData(ans);
    }

//    @GetMapping("work/query")
//    public ResponseDTO getLockedFlow(@RequestParam("flowWorkIds") List<Long> flowWorkIds){
//
//    }

    /**
     * 查询流程实例参数
     */
    @GetMapping("work/{id}/params")
    @ApiOperation(value = "查询流程实例参数",notes = "传入ID")
    public ResponseDTO<FlowParam> getFlowWorkParams(@PathVariable("id") String id){
        Optional<FlowWork> flowWorkOp = flowWorkService.getById(id);
        return flowWorkOp.map(flowWork -> ResponseDTO.succData(JsonUtil.string2Obj(flowWork.getFlowParam(), FlowParam.class))).orElseGet(() -> ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND));
    }
    /**
     * 查询流程实例模型
     */
    @GetMapping("work/{id}/model")
    @ApiOperation(value = "查询流程实例模型",notes = "传入ID")
    public ResponseDTO<FlowModel> getFlowWorkModel(@PathVariable("id") String id) throws IOException {
        Optional<FlowWork> flowWorkOp = flowWorkService.getById(id);
        if (flowWorkOp.isPresent()){
            return ResponseDTO.succData(flowNodeParser.parser(flowWorkOp.get().getFlowDefine()));
        }else {
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        }
    }

    /**
     * 查询流程实例列表
     */
    @GetMapping("work")
    @ApiOperation(value = "查询流程实例列表",notes = "")
    public ResponseDTO getFlowWorkList(FlowWorkQueryDTO dto){

        Sort sort;
        if(dto.getOrder().equalsIgnoreCase("DESC")){
            sort = Sort.by(Sort.Direction.DESC, dto.getSortBy());
        }else {
            sort = Sort.by(Sort.Direction.ASC, dto.getSortBy());
        }

        // tips : 页码对应 - 1
        Pageable pageable = PageRequest.of(dto.getPageNum() - 1 , dto.getPageSize(), sort);
        FlowWork flowWork = new FlowWork();
        BeanUtil.copyProperties(dto,flowWork, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        Example<FlowWork> example = Example.of(flowWork);
        return flowWorkService.getAll(pageable,example);
    }
    /**
     * 根据流程实例信息，获取对应的关联实体
     */
    @GetMapping("work/{workId}/entity")
    @ApiOperation(value = "查询流程实例关联实体",notes = "")
    public ResponseDTO getWorkEntity(@PathVariable("workId") String workId){
        Optional<FlowWork> flowWorkOp = flowWorkService.getById(workId);
        if (!flowWorkOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        }
        FlowWork flowWork = flowWorkOp.get();
        FlowParam param = JsonUtil.string2Obj(flowWork.getFlowParam(),FlowParam.class);
        return entityService.getNepuEntity(param.getServiceType(),param.getServiceId());
    }


    @SaCheckRole("admin")
    @WebLog(module = "bone-flow",operate = MethodTypeConst.INSERT)
    @PostMapping("work/{workId}/createTask")
    @ApiOperation(value = "创建流程审核任务")
    public ResponseDTO<Object> flowWorkTaskCreate(@PathVariable("workId") String workId) throws IOException {
        Optional<FlowWork> flowWorkOp = flowWorkService.getById(workId);
        if (!flowWorkOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        }
        FlowWork flowWork = flowWorkOp.get();
        FlowParam param = JsonUtil.string2Obj(flowWork.getFlowParam(),FlowParam.class);

        if (!flowWork.getFlowWorkStatus().equals(FlowWorkStatusConst.IN_PROGRESS) || !flowWork.getStatus().equals(1)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"当前状态无法创建TASK");
        }

        /**
         * 从 task 中查询当前节点有无指派审核人员
         */
        List<FlowTask> tasks = taskService.getByFlowWorkIdAndFlowNodeId(workId,flowWork.getCurrentNodeId());

        List<String> deleteIds = new ArrayList<>();

        tasks.forEach(ele->{
            if (ele.getTaskStatus().equals(FlowTaskStatusConst.CREATED)) deleteIds.add(ele.getId());
        });

//        if (tasks.size() != 0){
//            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"已存在TASK，禁止重复创建");
//        }
        // 清空原有记录 -- 根据id 列表删除

        taskService.deleteList(deleteIds);

        // 获取总节点结构
        FlowModel flowModel = flowNodeParser.parser(flowWork.getFlowDefine());

        // 获取当前节点信息
        BaseModel currentModel = flowModel.getNodeModel(flowWork.getCurrentNodeId());

        taskNodeProcessor.createTask(flowWork,param, (TaskModel) currentModel);

        //List<String> userIds = flowNodeUserLoader.loadUsers(flowWork,currentModel,null);

        tasks = taskService.getByFlowWorkIdAndFlowNodeId(workId,flowWork.getCurrentNodeId());


        return ResponseDTO.succData(tasks);
    }


}
